//---------------------------------------------------------------------------
/** Susieプラグイン管理クラス
 */
//---------------------------------------------------------------------------
/*
 * Copyright (c) 1999 - 2005 shimitei
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
//---------------------------------------------------------------------------
#include <stdio.h>
#include <vcl.h>
#pragma hdrstop

#include "spi_manage.h"
#include "misc.h"

/* グローバル */
ASpiManager g_spiManager ;
//---------------------------------------------------------------------------
/** 特に何もしないコールバック関数
 * コールバックを指定しないと落ちるプラグインがあるため
 */
static int __stdcall nopSpiCallback(int nNum, int nDenom, long lData)
{
    return 0 ;
}
//---------------------------------------------------------------------------
/** デストラクタ
 * プラグインを解放
 */
ASpiManager::~ASpiManager()
{
    std::vector<APluginSusie *>::iterator ite ;
    if ( ! m_array00IN.empty() )
    {
        for (ite = m_array00IN.begin(); ite != m_array00IN.end(); ite++)
        {
            delete *ite ;
        }
    }
    if ( ! m_array00AM.empty() )
    {
        for (ite = m_array00AM.begin(); ite != m_array00AM.end(); ite++)
        {
            delete *ite ;
        }
    }
}
//---------------------------------------------------------------------------
/** 指定フォルダにあるSusieプラグインをロードする
 * @param path \\で終わるフォルダのパス
 */
void __fastcall ASpiManager::loadAll(const char *path)
{
    AnsiString findpath = (AnsiString)path + "*.spi" ;
    loadSpi( findpath.c_str() ) ;
}
//---------------------------------------------------------------------------
/** 指定パスのプラグインをロードする
 * @param path ワイルドカード有効
 */
void __fastcall ASpiManager::loadSpi(const char *path)
{
    AnsiString spipath ;
    AnsiString pathdir = ExtractFilePath( path ) ;

    WIN32_FIND_DATA ff ;
    HANDLE hf = FindFirstFile( path, &ff ) ;
    if ( hf == INVALID_HANDLE_VALUE ) return ;

    while ( hf != INVALID_HANDLE_VALUE )
    {
        APluginSusie *spi = new APluginSusie ;
        spipath = pathdir + ff.cFileName ;

        if ( ! spi->load( spipath.c_str() ) )
        {
            delete spi ;
        }
        else
        {
            if ( spi->getType() == TYPE_00AM )
            {
                m_array00AM.push_back( spi ) ;
                m_count00AM++ ;
            }
            else
            {
                m_array00IN.push_back( spi ) ;
                m_count00IN++ ;
            }
        }
        if ( FindNextFile( hf, &ff ) == 0 ) break ;
    }
    FindClose( hf ) ;
}
//---------------------------------------------------------------------------
/** Susieプラグインの情報を得る
 * @param pcspi プラグインクラス
 * @param infoNum 情報番号
 * @param buf 情報を書き込むバッファ
 * @param buflen bufのサイズ
 */
bool __fastcall ASpiManager::getPluginInfo(APluginSusie *pcspi,
                    const int infoNum, const LPSTR buf, const int buflen)
{
    bool ret = false ;

    if ( pcspi != NULL )
    {
        try
        {
            ret = pcspi->GetPluginInfo( infoNum, buf, buflen ) ;
        }
        catch (...)
        {
            //throw ;
        }
    }
    return ret ;
}
//---------------------------------------------------------------------------
/** プラグインの情報を得る
 * getPluginInfo()のラップ
 * @param num プラグイン配列のインデックス番号
 * @param infoNum 情報番号
 */
AnsiString __fastcall ASpiManager::getSpiInfo(int num, int infoNum)
{
    AnsiString retstr = "" ;

    if ( ! boundCheck( num ) ) retstr ;

    APluginSusie *pspi ;
    const infoBufSize = 512 ;
    const buflen = infoBufSize -1 ; // プラグイン側で終端があいまいでも大丈夫
    char buf[ infoBufSize ] = "" ;

    // 00AMからカウント
    if ( num < m_count00AM )
    {
        pspi = m_array00AM[ num ] ;
    }
    else
    {
        pspi = m_array00IN[ num - m_count00AM ] ;
    }
    if ( getPluginInfo( pspi, infoNum, buf, buflen ) )
    {
        buf[ buflen ] = '\0' ; // プラグインは信用しない
        retstr = buf ;
    }

    return retstr ;
}
//---------------------------------------------------------------------------
/** ファイルの展開チェック
 * @param src ファイルパス
 * @param mem メモリデータ
 * @return 対応しているプラグインクラスへのポインタを返す
 *         非対応はNULLを返す
 */
APluginSusie* __fastcall ASpiManager::filecheck(char *src, char *mem)
{
    const headerBufSize = 4000 ;
    char data[ headerBufSize ] ;
    char *pdata ;

    if ( mem == NULL )
    {
        /* ファイル入力 */
        FILE *fp = fopen( src, "rb" ) ;
        if ( fp == NULL ) return NULL ;
        fread( data, 1, headerBufSize, fp ) ;
        fclose( fp ) ;
        pdata = data ;
    }
    else
    {
        /* メモリ入力 */
        pdata = mem ;
    }

    // 00AM優先
    std::vector<APluginSusie *>::iterator ite ;
    for (ite = m_array00AM.begin(); ite != m_array00AM.end(); ite++)
    {
        try
        {
            if ( *ite != NULL )
            {
                if ( (*ite)->IsSupported( src, (DWORD)pdata ) != 0 )
                {
                    return  *ite ;
                }
            }
        }
        catch (...)
        {
            //throw ;
        }
    }

    // 00IN
    for (ite = m_array00IN.begin(); ite != m_array00IN.end(); ite++) {
        try
        {
            if ( *ite != NULL )
            {
                if ( (*ite)->IsSupported( src, (DWORD)pdata ) != 0 )
                {
                    return *ite ;
                }
            }
        }
        catch (...)
        {
            //throw ;
        }
    }

    return NULL ;
}
//---------------------------------------------------------------------------
/** 画像の情報を得る
 * @param pcspi プラグインクラスへのポインタ
 * @param buf ファイルパスまたはメモリデータへのポインタ
 * @param len
 * @param flag
 * @param lpInfo 返却するPictureInfoデータへのポインタ
 * @return エラーコード
 */
int __fastcall ASpiManager::spi_picinfo(APluginSusie *pcspi,
                   const LPSTR buf, const long len, const DWORD flag,
                      PictureInfo *lpInfo)
{
    int ret = SPI_NO_FUNCTION ;

    if ( pcspi == NULL )
    {
        if ( IS_FILEIN( flag ) )
        {
            // ディスクファイル
            pcspi = filecheck( buf, NULL ) ;
        }
        else
        {
            // メモリ上のイメージ
            pcspi = filecheck( NULL, buf ) ;
        }
        if ( pcspi == NULL ) return SPI_NOT_SUPPORT ;
    }

    if ( pcspi->getType() == TYPE_00IN )
    {
        try
        {
            ret = pcspi->GetPictureInfo( buf, len, flag, lpInfo ) ;
        }
        catch (...)
        {
            ret = SPI_FATAL_ERR ;
            //throw ;
        }
    }

    return ret ;
}
//---------------------------------------------------------------------------
/** 画像を得る
 * @param pcspi プラグインクラスへのポインタ
 * @param buf ファイルパスまたはメモリデータへのポインタ
 * @param len
 * @param flag
 * @param pHBInfo 返却するBITMAPINFOデータハンドルへのポインタ
 * @param pHBm 返却するビットマップデータハンドルへのポインタ
 * @param lpPrgressCallback コールバック関数
 * @param lData コールバック関数に渡すデータ
 * @return エラーコード
 */
int __fastcall ASpiManager::spi_pic(APluginSusie *pcspi,
                     const LPSTR buf, const long len, const DWORD flag,
                     HANDLE *pHBInfo, HANDLE *pHBm,
                     SPI_PROGRESS lpPrgressCallback, const long lData)
{
    int ret = SPI_NO_FUNCTION ;

    if ( pcspi == NULL )
    {
        if ( IS_FILEIN( flag ) )
        {
            // ディスクファイル
            pcspi = filecheck( buf, NULL ) ;
        }
        else
        {
            // メモリ上のイメージ
            pcspi = filecheck( NULL, buf ) ;
        }
        if ( pcspi == NULL ) return ret ;
    }

    if ( pcspi->getType() == TYPE_00IN )
    {
        if ( lpPrgressCallback == NULL )
        {
            lpPrgressCallback = nopSpiCallback ;
        }
        try
        {
            ret = pcspi->GetPicture( buf, len, flag, pHBInfo, pHBm,
                               lpPrgressCallback, lData ) ;
        }
        catch (...)
        {
            ret = SPI_FATAL_ERR ;
            //throw;
        }
    }

    return ret ;
}
//---------------------------------------------------------------------------
/** プレビュー画像を得る
 * @param pcspi プラグインクラスへのポインタ
 * @param buf ファイルパスまたはメモリデータへのポインタ
 * @param len
 * @param flag
 * @param pHBInfo 返却するBITMAPINFOデータハンドルへのポインタ
 * @param pHBm 返却するビットマップデータハンドルへのポインタ
 * @param lpPrgressCallback コールバック関数
 * @param lData コールバック関数に渡すデータ
 * @return エラーコード
 */
int __fastcall ASpiManager::spi_prev(APluginSusie *pcspi,
                     const LPSTR buf, const long len, const DWORD flag,
                     HANDLE *pHBInfo, HANDLE *pHBm,
                     SPI_PROGRESS lpPrgressCallback, const long lData)
{
    int ret = SPI_NO_FUNCTION ;

    if ( pcspi == NULL )
    {
        if ( IS_FILEIN( flag ) )
        {
            // ディスクファイル
            pcspi = filecheck( buf, NULL ) ;
        }
        else
        {
            // メモリ上のイメージ
            pcspi = filecheck( NULL, buf ) ;
        }
        if ( pcspi == NULL ) return ret ;
    }

    if ( pcspi->getType() == TYPE_00IN )
    {
        if ( lpPrgressCallback == NULL)
        {
            lpPrgressCallback = nopSpiCallback ;
        }
        try
        {
            ret = pcspi->GetPreview( buf, len, flag, pHBInfo, pHBm,
                               lpPrgressCallback, lData ) ;
            if ( ret == SPI_NO_FUNCTION )
            {
                ret = pcspi->GetPicture( buf, len, flag, pHBInfo, pHBm,
                               lpPrgressCallback, lData ) ;
            }
        }
        catch (...)
        {
            ret = SPI_FATAL_ERR ;
            //throw ;
        }
    }

    return ret ;
}
//---------------------------------------------------------------------------
/** アーカイブの情報を得る
 * @param pcspi プラグインクラスへのポインタ
 * @param buf ファイルパスまたはメモリデータへのポインタ
 * @param len
 * @param flag
 * @param pHBInfo 返却するfileInfo配列データハンドルへのポインタ
 * @return エラーコード
 */
int __fastcall ASpiManager::spi_arcinfo(APluginSusie *pcspi,
                      const LPSTR buf, const long len,
                      const DWORD flag, HLOCAL *lphInf)
{
    int ret = SPI_NO_FUNCTION ;

    if ( pcspi == NULL )
    {
        if ( IS_FILEIN( flag ) )
        {
            // ディスクファイル
            pcspi = filecheck( buf, NULL ) ;
        }
        else
        {
            // メモリ上のイメージ
            pcspi = filecheck( NULL, buf ) ;
        }
        if ( pcspi == NULL ) return ret ;
    }

    if ( pcspi->getType() == TYPE_00AM )
    {
        *lphInf = NULL ; // for lhasad.spi
        try
        {
            ret = pcspi->GetArchiveInfo( buf, len, flag, lphInf ) ;
            // for lhasad.spi's bug
            if ( ret == SPI_NOT_SUPPORT && *lphInf != NULL )
            {
                ret = SPI_ALL_RIGHT ;
            }
        }
        catch (...)
        {
            ret = SPI_FATAL_ERR ;
            //throw ;
        }
    }

    return ret ;
}
//---------------------------------------------------------------------------
/** アーカイブ内ファイルの情報を得る
 * @param pcspi プラグインクラスへのポインタ
 * @param buf ファイルパスまたはメモリデータへのポインタ
 * @param len
 * @param filename 調べるアーカイブ内ファイル名
 * @param flag
 * @param pHBInfo 返却するfileInfoデータへのポインタ
 * @return エラーコード
 */
int __fastcall ASpiManager::spi_fileinfo(APluginSusie *pcspi,
                    const LPSTR buf, const long len, const LPSTR filename,
                    const DWORD flag, fileInfo *lpInfo)
{
    int ret = SPI_NO_FUNCTION ;

    if ( pcspi == NULL )
    {
        if ( IS_FILEIN( flag ) )
        {
            // ディスクファイル
            pcspi = filecheck( buf, NULL ) ;
        }
        else
        {
            // メモリ上のイメージ
            pcspi = filecheck( NULL, buf ) ;
        }
        if ( pcspi == NULL ) return ret ;
    }

    if ( pcspi->getType() == TYPE_00AM )
    {
        try
        {
            ret = pcspi->GetFileInfo( buf, len, filename, flag, lpInfo ) ;
        }
        catch (...)
        {
            ret = SPI_FATAL_ERR ;
            //throw ;
        }
    }

    return ret ;
}
//---------------------------------------------------------------------------
/** アーカイブ内のファイルを得る
 * @param pcspi プラグインクラスへのポインタ
 * @param buf ファイルパスまたはメモリデータへのポインタ
 * @param len
 * @param dest
 * @param flag
 * @param pHBInfo 返却するfileInfoデータへのポインタ
 * @return エラーコード
 */
int __fastcall ASpiManager::spi_getfile(APluginSusie *pcspi,
                    const LPSTR src, const long len, const LPSTR dest, const DWORD flag,
                    SPI_PROGRESS lpPrgressCallback, const long lData)
{
    int ret = SPI_NO_FUNCTION ;

    if ( pcspi == NULL )
    {
        if ( IS_FILEIN( flag ) )
        {
            // ディスクファイル
            pcspi = filecheck( src, NULL ) ;
        } else {
            // メモリ上のイメージ
            pcspi = filecheck( NULL, src ) ;
        }
        if ( pcspi == NULL ) return ret ;
    }

    if ( pcspi->getType() == TYPE_00AM )
    {
        if ( lpPrgressCallback == NULL)
        {
            lpPrgressCallback = nopSpiCallback ;
        }
        try
        {
           ret = pcspi->GetFile( src, len, dest, flag,
                        lpPrgressCallback, lData ) ;
        }
        catch (...)
        {
            ret = SPI_FATAL_ERR ;
            //throw ;
        }
    }

    return ret ;
}
//---------------------------------------------------------------------------
/** Susieプラグインの設定ダイアログを表示する
 * 配列からプラグインを設定してconfigDlg()に引き渡す
 * @param num プラグイン配列のインデックス番号
 * @param parent ダイアログの親ウィンドウハンドル
 * @param func ダイアログ番号
 */
bool __fastcall ASpiManager::spiConfig(const int num, const HWND parent, const int func)
{
    if ( ! boundCheck( num ) ) return false ;

    APluginSusie *pcspi ;
    if ( num < m_count00AM )
    {
        pcspi = m_array00AM[ num ] ;
    }
    else
    {
        pcspi = m_array00IN[ num - m_count00AM ] ;
    }

    return configDlg( pcspi, parent, func ) ;
}
//---------------------------------------------------------------------------
/** Susieプラグインの設定ダイアログを表示する
 * @param pcspi プラグインクラス
 * @param parent ダイアログの親ウィンドウハンドル
 * @param func ダイアログ番号
 */
bool __fastcall ASpiManager::configDlg(APluginSusie *pcspi, const HWND parent, const int func)
{
    bool ret = false ;
    if ( pcspi == NULL ) return ret ;
    if ( pcspi->ConfigurationDlg != NULL )
    {
        try
        {
            if ( pcspi->ConfigurationDlg( parent, func ) != 0 )
            {
                ret = true ;
            }
        }
        catch (...)
        {
            //throw ;
        }
    }

    return ret ;
}
//---------------------------------------------------------------------------


/** パスから画像を得る
 * 書庫内書庫内対応
 * @return エラーコードを返す
 */
int __fastcall ASpiManager::spi2dib(const AnsiString &filename,
    HANDLE *pHBInfo, HANDLE *pHBm, HANDLE *pHfile, const bool preview)
{
    //対応チェック
    int ret;
    APluginSusie *pcspi;
    char *pfimg = NULL;
    AnsiString tmpname = filename;
    AnsiString arcpath = ""; //書庫内のパス
    unsigned int flag = SPI_FLAG_FILE;
    ret = ExistsCheck(tmpname);
if (pHfile == NULL && ret != NO_EXISTS) {
//ファイルのパスから変換
    if (ret == IS_DIR) {
        //フォルダは無いだろう...
        return SPI_FILE_READ_ERROR;
    }
    //ファイルが存在する
    //DIBゲット
    pcspi = filecheck(tmpname.c_str(), pfimg);
    if (pcspi->getType() == TYPE_00IN) {
        if (preview) {
            ret = spi_prev(pcspi, tmpname.c_str(), 0, flag, pHBInfo, pHBm, NULL, 0);
            if (ret != SPI_ALL_RIGHT) {
                ret = spi_pic(pcspi, tmpname.c_str(), 0, flag, pHBInfo, pHBm, NULL, 0);
            }
        } else {
            ret = spi_pic(pcspi, tmpname.c_str(), 0, flag, pHBInfo, pHBm, NULL, 0);
        }
    } else {
        return SPI_NOT_SUPPORT;
    }
    return ret;

}

//メモリイメージから変換
    flag = SPI_FLAG_MEM;
if (tmpname == "") {
    //イメージはファイルらしい
    //DIBゲット
    pfimg = (char *)LocalLock(*pHfile);
    pcspi = filecheck(tmpname.c_str(), pfimg);
    if (pcspi->getType() == TYPE_00IN) {
        if (preview) {
            ret = spi_prev(pcspi, pfimg, LocalSize(*pHfile), flag, pHBInfo, pHBm, NULL, 0);
            if (ret != SPI_ALL_RIGHT) {
                ret = spi_pic(pcspi, pfimg, LocalSize(*pHfile), flag, pHBInfo, pHBm, NULL, 0);
            }
        } else {
            ret = spi_pic(pcspi, pfimg, LocalSize(*pHfile), flag, pHBInfo, pHBm, NULL, 0);
        }
        LocalUnlock(*pHfile);
        return ret;
    }
    LocalUnlock(*pHfile);
    return SPI_NOT_SUPPORT;
}

//指定ファイルを取り出す
    HANDLE dest = NULL;
    ret = GetFileEx(tmpname, "", pHfile, &dest);
    if (ret != SPI_ALL_RIGHT) {
        if (dest != NULL) LocalFree(dest);
        return ret;
    }
    ret = spi2dib("", pHBInfo, pHBm, &dest, preview);
    if (dest != NULL) LocalFree(dest);
    return ret;
}
//---------------------------------------------------------------------------
//書庫からファイルを得る（書庫内書庫対応）
//エラーコードを返す
//filename:欲しいファイルのパス
//arcname:欲しい書庫内のパス。再帰用。普通は""を入れてね
//HANDLE *src:書庫イメージ。ファイル入力はNULL！
//HANDLE *dest:返却用
int __fastcall ASpiManager::GetFileEx(const AnsiString &filename, const AnsiString &arcname,
                   HANDLE *src, HANDLE *dest)
{
    int ret;
    APluginSusie *pcspi;
    fileInfo finfo;
    HANDLE htmp = NULL;
    AnsiString tmpname = filename;
    AnsiString arcpath = arcname;

if (arcpath == "") {
    //ファイル入力
    //おおもとの書庫を特定
for (;;) {
    ret = ExistsCheck(tmpname);
    if (ret == NO_EXISTS) {
        //書庫内ファイルを指定してるのかも
        if (arcpath != "") arcpath = "\\" +arcpath;
        arcpath = ExtractFileName(tmpname) +arcpath;
        tmpname = ExtractDirName(tmpname);
        if (tmpname.Length() <= 3) {
            //勘違い？
            return SPI_FILE_READ_ERROR;
        }
    } else if (ret == IS_FILE) {
        //ファイルが存在する
        //チェックしないと無限再帰してスタックオーバーフロー
        if (arcpath == "") return SPI_NOT_SUPPORT;
        break;
    } else {
        //フォルダは無いだろう...
        return SPI_FILE_READ_ERROR;
    }
} //end for (;;)
    //再帰
    //arcpath:書庫内パス
    //tmpname:書庫ファイル名
    ret = GetFileEx(tmpname, arcpath, NULL, dest);
    return ret;
}

if (src == NULL) {
    //ファイル入力
    //書庫は特定済み
    //指定ファイルは書庫にあるか？
    pcspi = filecheck(tmpname.c_str(), NULL);
    if (pcspi->getType() != TYPE_00AM) {
        return SPI_NOT_SUPPORT;
    }
    memset(&finfo, 0, sizeof(finfo));
    ret = spi_fileinfo(pcspi, tmpname.c_str(), 0, arcpath.c_str(), SPI_FLAG_FILE, &finfo);
    if (ret == SPI_ALL_RIGHT) {
        ret = spi_getfile(pcspi, tmpname.c_str(), finfo.position, (char *)dest, SPI_FLAG_OUTMEM, NULL, 0);
        if (ret != SPI_ALL_RIGHT) {
            return ret;
        }
        return ret;
    }
for (;;) {
    //書庫内書庫を特定
    int ofset = arcpath.AnsiPos("\\");
    if (ofset == 0) {
        //無いじゃん...
        return SPI_FILE_READ_ERROR;
    }
    tmpname = arcpath.SubString(1, ofset -1);
    arcpath = arcpath.SubString(ofset +1, arcpath.Length() -ofset);
    memset(&finfo, 0, sizeof(finfo));
    ret = spi_fileinfo(pcspi, filename.c_str(), 0, tmpname.c_str(), SPI_FLAG_FILE, &finfo);
    if (ret == SPI_ALL_RIGHT) {
        ret = spi_getfile(pcspi, filename.c_str(), finfo.position, (char *)&htmp, SPI_FLAG_OUTMEM, NULL, 0);
        if (ret != SPI_ALL_RIGHT) {
            return ret;
        }
        //さらに再帰
        ret = GetFileEx("", arcpath, &htmp, dest);
        LocalFree(htmp);
        return ret;
    }
} //end for (;;)
}

    //メモリ入力
    //書庫は特定済み
    //指定ファイルは書庫にあるか？
    char *pfimg = (char *)LocalLock(*src);
    pcspi = filecheck(tmpname.c_str(), pfimg);
    if (pcspi->getType() != TYPE_00AM) {
        LocalUnlock(*src);
        return SPI_NOT_SUPPORT;
    }
    memset(&finfo, 0, sizeof(finfo));
    ret = spi_fileinfo(pcspi, pfimg, LocalSize(*src), arcpath.c_str(), SPI_FLAG_MEM, &finfo);
    if (ret == SPI_ALL_RIGHT) {
        ret = spi_getfile(pcspi, pfimg +finfo.position, LocalSize(*src) -finfo.position, (char *)dest, SPI_FLAG_OUTMEM | SPI_FLAG_MEM, NULL, 0);
        LocalUnlock(*src);
        if (ret != SPI_ALL_RIGHT) {
            return ret;
        }
        return ret;
    }
for (;;) {
    //書庫内書庫を特定
    int ofset = arcpath.AnsiPos("\\");
    if (ofset == 0) {
        //無いじゃん...
        LocalUnlock(*src);
        return SPI_FILE_READ_ERROR;
    }
    tmpname = arcpath.SubString(0, ofset -1);
    arcpath = arcpath.SubString(ofset +1, arcpath.Length() -ofset -1);
    memset(&finfo, 0, sizeof(finfo));
    ret = spi_fileinfo(pcspi, pfimg, LocalSize(*src), arcpath.c_str(), SPI_FLAG_MEM, &finfo);
    if (ret == SPI_ALL_RIGHT) {
        ret = spi_getfile(pcspi, pfimg +finfo.position, LocalSize(*src) -finfo.position, (char *)&htmp, SPI_FLAG_OUTMEM | SPI_FLAG_MEM, NULL, 0);
        LocalUnlock(*src);
        if (ret != SPI_ALL_RIGHT) {
            return ret;
        }
        //さらに再帰
        ret = GetFileEx("", arcpath, &htmp, dest);
        LocalFree(htmp);
        return ret;
    }
} //end for (;;)
}
//---------------------------------------------------------------------------

